package com.apobates.jforum2.troll.threads.biz.impl.dao;

import com.apobates.jforum2.troll.threads.biz.dao.TopicStatsDao;
import com.apobates.jforum2.troll.threads.entity.TopicStats;
import java.time.LocalDateTime;
import java.util.Collection;
import java.util.Optional;
import java.util.stream.Stream;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

/**
 *
 * @author xiaofanku
 * @since 20200513
 */
@Repository
public class TopicStatsDaoImpl implements TopicStatsDao{
    @PersistenceContext
    private EntityManager entityManager;
    private final static Logger logger = LoggerFactory.getLogger(TopicStatsDaoImpl.class);

    /**
     * 
     * @param topicId
     * @param volumesId
     * @param boardId
     * @return 
     */
    @Transactional(propagation = Propagation.REQUIRED)
    @Override
    public Optional<Boolean> createStats(long topicId, int volumesId, long boardId) {
        try {
            entityManager.persist(new TopicStats(topicId, volumesId, boardId));
            return Optional.of(true);
        } catch (Exception e) {
            if(logger.isDebugEnabled()){
                logger.debug(e.getMessage(), e);
            }
            return Optional.empty();
        }
    
    }
    @Transactional(propagation = Propagation.REQUIRED)
    @Override
    public Optional<Boolean> createStats(long topicId, int volumesId, long boardId, long topicMemberId, String topicMemberNickname) {
        try {
            entityManager.persist(TopicStats.init(topicId, topicMemberId, topicMemberNickname, volumesId, boardId));
            return Optional.of(true);
        } catch (Exception e) {
            if(logger.isDebugEnabled()){
                logger.debug(e.getMessage(), e);
            }
            return Optional.empty();
        }
    }
    
    @Transactional(propagation = Propagation.REQUIRED)
    @Override
    public Optional<Boolean> updatePosts(long topicId, long recentPostsMemberId, String recentPostsMemberNickname, LocalDateTime recentPostsDate, long recentPostsId) {
        try {
            int tsAffect = entityManager.createQuery("UPDATE TopicStats ts SET ts.postses = ts.postses + 1, ts.recentPostsMemberId = ?1, ts.recentPostsMemberNickname = ?2, ts.recentPostsDate = ?3, ts.updateDate = ?4, ts.recentPostsId = ?5 WHERE ts.topicId = ?6")
                    .setParameter(1, recentPostsMemberId)
                    .setParameter(2, recentPostsMemberNickname)
                    .setParameter(3, recentPostsDate)
                    .setParameter(4, LocalDateTime.now())
                    .setParameter(5, recentPostsId)
                    .setParameter(6, topicId)
                    .executeUpdate();
            int tAffect = entityManager.createQuery("UPDATE Topic t SET t.rankingDateTime = ?1 WHERE t.id = ?2").setParameter(1, recentPostsDate).setParameter(2, topicId).executeUpdate();
            return (tsAffect == 1 && tsAffect == tAffect) ? Optional.of(true) : Optional.empty();
        } catch (Exception e) {
            if(logger.isDebugEnabled()){
                logger.debug(e.getMessage(), e);
            }
            return Optional.empty();
        }
    }

    @Transactional(propagation = Propagation.REQUIRED)
    @Override
    public void plusFavorites(long topicId)throws IllegalStateException {
        int affect = entityManager
                    .createQuery("UPDATE TopicStats ts SET ts.favorites = ts.favorites + 1, ts.updateDate = ?1 WHERE ts.topicId = ?2")
                    .setParameter(1, LocalDateTime.now())
                    .setParameter(2, topicId)
                    .executeUpdate();
        if(affect!=1){
            throw new IllegalStateException("[plus]更新话题收藏统计失败");
        }
    }

    @Transactional(propagation = Propagation.REQUIRED)
    @Override
    public void negateFavorites(long topicId)throws IllegalStateException {
        int affect = entityManager
                    .createQuery("UPDATE TopicStats ts SET ts.favorites = ts.favorites - 1, ts.updateDate = ?1 WHERE ts.topicId = ?2")
                    .setParameter(1, LocalDateTime.now())
                    .setParameter(2, topicId)
                    .executeUpdate();
        if(affect!=1){
            throw new IllegalStateException("[negate]更新话题收藏统计失败");
        }
    }
    
    @Transactional(propagation = Propagation.REQUIRED)
    @Override
    public Optional<Boolean> updateDisplaies(long topicId) {
        //是否达到火贴的标准了
        TopicStats ts = findOneByTopic(topicId).orElseGet(() -> null);
        if (null == ts) {
            return Optional.empty();
        }
        if (ts.getDisplaies() > 300) {
            entityManager.createQuery("UPDATE Topic t SET t.hots = ?1 WHERE t.hots = ?2 AND t.id = ?3").setParameter(1, true).setParameter(2, false).setParameter(3, topicId).executeUpdate();
        }
        try {
            ts.setDisplaies(ts.getDisplaies() + 1);
            ts.setUpdateDate(LocalDateTime.now());
            entityManager.merge(ts);
            return Optional.of(true);
        } catch (Exception e) {
            if(logger.isDebugEnabled()){
                logger.debug(e.getMessage(), e);
            }
            return Optional.empty();
        }
    }

    @Transactional(propagation = Propagation.REQUIRED)
    @Override
    public void plusLikes(long topicId)throws IllegalStateException {
        int affect = entityManager
                    .createQuery("UPDATE TopicStats ts SET ts.likes = ts.likes + 1, ts.updateDate = ?1 WHERE ts.topicId = ?2")
                    .setParameter(1, LocalDateTime.now())
                    .setParameter(2, topicId)
                    .executeUpdate();
        if(affect!=1){
            throw new IllegalStateException("[plus]更新话题点赞统计失败");
        }
    }

    @Transactional(propagation = Propagation.REQUIRED)
    @Override
    public void negateLikes(long topicId)throws IllegalStateException {
        int affect = entityManager
                    .createQuery("UPDATE TopicStats ts SET ts.likes = ts.likes - 1, ts.updateDate = ?1 WHERE ts.topicId = ?2")
                    .setParameter(1, LocalDateTime.now())
                    .setParameter(2, topicId)
                    .executeUpdate();
        if(affect!=1){
            throw new IllegalStateException("[negate]更新话题点赞统计失败");
        }
    }
    
    @Override
    public Stream<TopicStats> findAllByTopicId(Collection<Long> topicIdList) {
        if (topicIdList == null || topicIdList.isEmpty()) {
            return Stream.empty();
        }
        return entityManager.createQuery("SELECT ts FROM TopicStats ts WHERE ts.topicId IN ?1", TopicStats.class).setParameter(1, topicIdList).getResultStream();
    }
    
    @Override
    public Stream<TopicStats> findAllByReplyDate(int size) {
        return entityManager.createQuery("SELECT ts FROM TopicStats ts ORDER BY ts.updateDate DESC", TopicStats.class).setMaxResults(size).getResultStream();
    }
    
    @Override
    public Optional<TopicStats> findOneByTopic(long topicId) {
        try {
            TopicStats ts = entityManager.createQuery("SELECT ts FROM TopicStats ts WHERE ts.topicId = ?1", TopicStats.class).setParameter(1, topicId).getSingleResult();
            return Optional.ofNullable(ts);
        } catch (javax.persistence.NoResultException e) {
            if(logger.isDebugEnabled()){
                logger.debug(e.getMessage(), e);
            }
            return Optional.empty();
        }
    }
    
    @Transactional(propagation = Propagation.REQUIRED)
    @Override
    public void save(TopicStats entity) {
        entityManager.persist(entity);
    }
    
    @Override
    public Optional<TopicStats> findOne(Long primaryKey) {
        return Optional.empty();
    }
    
    @Override
    public Optional<Boolean> edit(TopicStats updateEntity) {
        return Optional.empty();
    }
    
    @Override
    public Stream<TopicStats> findAll() {
        return Stream.empty();
    }
    
    @Override
    public long count() {
        return -1L;
    }
}